﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Windows.Data;
using System.Collections;
using System.Collections.ObjectModel;

namespace Wimat.Collections
{
    public class RandomizedCollectionView : ListCollectionView
    {
        #region .ctor
        public RandomizedCollectionView(IList list)
            : base(list)
        {
            _random = new Random();
            _usedIndexes = new Dictionary<int, object>();
            _RandomizedEditable = new ObservableCollection<object>();
            _RandomizedObservable = new ReadOnlyObservableCollection<object>(_RandomizedEditable);
        }
        #endregion

        #region Members

        private readonly Random _random;
        private readonly Dictionary<int, object> _usedIndexes;
        private readonly ObservableCollection<object> _RandomizedEditable;
        private readonly ReadOnlyObservableCollection<object> _RandomizedObservable;

        #endregion

        public ReadOnlyObservableCollection<object> Randomized
        {
            get { return _RandomizedObservable; }
        }

        private int _RandomizedExpectedCount;
        public int RandomizedExpectedCount
        {
            get { return _RandomizedExpectedCount; }
            set
            {
                if (_RandomizedExpectedCount != value)
                {
                    if (value <= 0) throw new ArgumentOutOfRangeException();
                    _RandomizedExpectedCount = value;
                    Randomize();
                }
            }
        }
        public void MoveCurrentToRandom()
        {
            var i = GetRandomIndex();
            var target = GetItemAt(i);
            MoveCurrentTo(target);
        }

        public void Randomize()
        {
            _usedIndexes.Clear();
            _RandomizedEditable.Clear();

            while (_RandomizedEditable.Count < _RandomizedExpectedCount
                && _RandomizedEditable.Count < Count)
            {
                int i = GetRandomUnusedIndex();
                var target = GetItemAt(i);
                _usedIndexes.Add(i, target);
                _RandomizedEditable.Add(target);
            }
        }
        private int GetRandomIndex()
        {
            int i = _random.Next(0, Count);
            return i;
        }
        private int GetRandomUnusedIndex()
        {
            if (_usedIndexes.Count >= Count) throw new InvalidOperationException();
            int i;
            do
            {
                i = _random.Next(0, Count);
            } while (_usedIndexes.ContainsKey(i));

            return i;
        }
    }
}
